package postpc.powerreminders.com.location;

import java.util.List;

import postpc.powerreminders.com.db.RotgDatabase;
import postpc.powerreminders.com.location.RotgLocationManager.LocationManagerCallback;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.util.Log;

/**
 * The WIFI controller class
 * 
 * In charge of running a periodic scan according to the power manager and 
 * alerting the Location manager in case that a reminder is required.
 *
 */
public class WIFIController extends BroadcastReceiver{

	/*
	 * Logger tag
	 */
	private static final String TAG = "ROTG_WIFIController";

	/*
	 * Reference to the WiFi manager for WiFi services.
	 */
	WifiManager wifiMan;

	/*
	 * Reference to the power manager.
	 */
	RotgPowerManager powerManager;

	/*
	 * Reference to the location manager.
	 */
	RotgLocationManager locationManager;

	/*
	 * Reference to the database.
	 */
	RotgDatabase dataBase;

	/*
	 * Handler for a delayed task.
	 */
	Handler handler = new Handler();
	
	/*
	 * Variables for returning
	 */
	private LocationManagerCallback callback = null;
	private boolean returnResults = false;
	int maxRssi = -1000;
	String bestBssid = "";
	String bestSsid = "";

	/**
	 * Constructor
	 * 
	 * @param mainActivity
	 * @param pm
	 */
	public WIFIController (RotgLocationManager lm, 
			RotgPowerManager pm, 
			RotgDatabase db) {

		super();
		Log.i(TAG, "Starting WIFI Controller");

		this.powerManager = pm;
		this.dataBase = db;
		this.locationManager = lm;

		// Register to receive scan done.
		enableScanAbility();

		// Get a handler to the android WiFi service
		wifiMan = (WifiManager) this.locationManager.context.getSystemService(Context.WIFI_SERVICE); 
	}

	/*
	 * Starts an immediate WiFi scan 
	 */
	public void startImmediateScan(){
		Log.i(TAG, "Wifi Scan start ...");
		wifiMan.startScan();
	}

	/*
	 * Cancels all previous deferred scan tasks and sets a new one.
	 * With the given interval
	 */
	public void resetScanInterval(long interval){
		Log.i(TAG, "Setting timer for " + interval);
		handler.removeCallbacks(updateTimeTask);
		handler.postDelayed(updateTimeTask, interval);
	}

	/**
	 * Stops the scan ability
	 */
	public void disableScaningAbility() {
		Log.i(TAG, "Disable scanning ability");
		handler.removeCallbacks(updateTimeTask);
	}

	/**
	 * Enable the scan ability
	 */
	protected void enableScanAbility() {
		Log.i(TAG, "Enabling scan ability");
		IntentFilter i = new IntentFilter(); 
		i.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 
		this.locationManager.context.registerReceiver(this, i); 
	}

	/**
	 * Close the W\WiFi controller.
	 */
	public void closeController() {
		Log.i(TAG, "Controller Service Closing");
		handler.removeCallbacks(updateTimeTask);
		this.locationManager.context.unregisterReceiver(this);
	}

	/**
	 * Handler for scan done request.
	 * Code to execute when SCAN_RESULTS_AVAILABLE_ACTION event occurs 
	 */
	public void onReceive(Context c, Intent i){ 
			
		Log.i(TAG, "Broadcast Reciever read");

		// WiFi manager for results
		WifiManager wm = (WifiManager) c.getSystemService(Context.WIFI_SERVICE); 

		// Returns a <list> of scanResults
		List<ScanResult> results = wm.getScanResults(); 
		Log.i(TAG, "Got Scan Results");

		// power management algorithm call
		this.powerManager.evaluateWifi(results);

		// Retrieve the BSSID
		for (ScanResult result : results) {
			//Log.i(TAG, "SSID: " + result.SSID + " BSSID: " + result.BSSID);
			Cursor cursor = dataBase.checkMacAddress(result.BSSID);
			if ( 0 != cursor.getCount()){
				Log.i(TAG, "BSSID: " + result.BSSID + " FOUND for location id " + cursor.getLong(0) );
				
				// ALERT 
				locationManager.notifyEventWifi(cursor);
				this.dataBase.deactivateReminderByLocation(cursor.getLong(0));
			}
		}
		disableScaningAbility();
		
		// User requested scan
		if (this.returnResults){
			maxRssi = -1000;
	
			for (ScanResult result : results){
				if (result.level > maxRssi){
					Log.w(TAG, "Updating Wifi level " + result.level + "for " + result.SSID);
					maxRssi = result.level;
					bestBssid = result.BSSID;
					bestSsid = result.SSID;
				}
			}
			
			if (results.size() != 0){
				this.callback.wifiInfoAvailable(bestSsid, bestBssid);
			}
			this.returnResults = false;
			this.callback = null;
		}
		
		if (this.powerManager.getWifiStayOnStatus()){
			Log.i(TAG, "Wifi stay active command");
			handler.postDelayed(updateTimeTask, powerManager.getWifiScanInterval());
		}
	}

	/**
	 * Task Handler for the WIFI differed task. 
	 */
	public Runnable updateTimeTask = new Runnable() {
		public void run() {
			Log.i(TAG, "Timer Called");
			try {
				enableScanAbility();
				startImmediateScan();
			}
			catch (Exception ex) {
				Log.e(TAG, "Error in timer callback", ex);
			}
		}
	};

	/*
	 * User requested last location
	 */
	public void requestCurrentLocation(LocationManagerCallback callback) {
		this.returnResults = true;
		this.callback = callback;
		handler.removeCallbacks(updateTimeTask);
		resetScanInterval(1);
	}
}